public class Element {
	
	public String name;
	public Map<String, String> attributes;
	public List<Element> children { 
		get {
			if (children == null) {
				children = new List<Element>();
			}
			return children;
		}
		set;
	}
	public String value;
	
	private Boolean readFirst = false;
	private String nodeName;
	
	public Element(XmlStreamReader reader, Integer hitMe) {
		readFirst = false;
		name = reader.getLocalName();
		parseXml(reader);
	}
	public Element(XmlStreamReader reader) {
		System.debug(LoggingLevel.INFO, '\n\nELEMENT CONSTRUCTOR - \n\tlocalName: ' + reader.getLocalName() + '\n\tEvent: ' + reader.getEventType() + '\n');
		name = reader.getLocalName();
		readFirst = true;
		parseXml(reader);
	} 
	private void parseXml(XmlStreamReader reader) {
		// add all attributes from this element
		attributes = new Map<String, String>();
		try {
			for (integer i=0; i<reader.getAttributeCount(); i++) { 
				System.debug(LoggingLevel.INFO, '\n\n\t [' + name.toUpperCase() + '] adding attribute ' + reader.getAttributeLocalName(i) + '=' + reader.getAttributeValueAt(i) + '\n');
			    attributes.put( reader.getAttributeLocalName(i), reader.getAttributeValueAt(i) );
			}
		} catch(Exception e) {
			System.debug(LoggingLevel.ERROR, '\n\n [' + name + '] ERROR READING ATTRIBUTES - IGNORE\n' + e.getMessage() + '\n');
		}
		System.debug(LoggingLevel.INFO, '\n\n\t\tRead first is ' + readFirst + ' - local name = ' + reader.getLocalName() + '\n');
		if (readFirst == true) {
			reader.next();
			System.debug(LoggingLevel.INFO, '\n\n\t\tAfter reader.next() in true readFirst - local name = ' + reader.getLocalName() + '\n\t\tEvent is: ' + reader.getEventType() + '\n');
		}
		nodeName = name;
		while (reader.hasNext()) {
            if (reader.getEventType() == XmlTag.START_ELEMENT) {
                nodeName = reader.getLocalName();
            	System.debug(LoggingLevel.FINE, '\n [' + name.toUpperCase() + '] Processing ' + reader.getLocalName() + ' - START');
                Element child = addChild(reader);
                System.debug(LoggingLevel.INFO, '\n\n [' + name.toUpperCase() + '] Finished adding ' + nodeName + '\n');
                //if (reader.hasNext()) {
                //	reader.next();
                //} else { 
                //	return;
                //}
            } else if (reader.getEventType() == XmlTag.CHARACTERS) {
            	System.debug(LoggingLevel.FINE, '\n [' + name.toUpperCase() + '] Processing ' + nodeName + ' - CHARS');
                if ( ! reader.isWhitespace() && reader.hasText()) {
                	if (value == null) {
                		value = reader.getText();
                	} else {
	                    value += reader.getText();  // add text to current element
                	}
                	System.debug(LoggingLevel.INFO, '\n\n\ttVALUE OF NODE ' + nodeName + ' IS: ' + value + '\n\n');
                }
                reader.next();
            } else if (reader.getEventType() == XmlTag.END_ELEMENT) {
            	System.debug(LoggingLevel.FINE, '\n [' + name.toUpperCase() + '] Processing ' + reader.getLocalName() + ' - END');
                //reader.next(); 
                //if (reader.getLocalName() == name) { 
	                return;
                //} 
            } else {
            	reader.next();
            }
		}
	}
	
	public Element addChild(XmlStreamReader reader) {
		Element c = new Element(reader);
		children.add(c);
		return c;
	}

	
}